<template>
  <div class="container">
    <div class="render">
      <kline-mock
          :list-a="data.klineA"
          :list-b="data.klineB"
          :show-x-point="false"
          :show-y-point="false"
          :x-axios="xAxiosArr"></kline-mock>
    </div>
    <div v-show="!data.selectorShow" class="controller">
      <bezier-selector @controllerPointChange="pointerChange"></bezier-selector>
      <mock-data-selector
          :end-x="data.taskDataSelector.endX"
          :rand="data.taskDataSelector.rand"
          :start-x="data.taskDataSelector.startX"
          :end-y="data.taskDataSelector.endY"
          :x-max="data.klineA.length"
          :x-min="0"
          @dataChange="mockSelectorChange">
      </mock-data-selector>
    </div>
  </div>
</template>
<script setup>
import KlineMock from "@/views/test/KlineMock";
import {computed, reactive} from "vue";
import BezierSelector from "@/components/common/BezierSelector";
import MockDataSelector from "@/components/common/MockDataSelector";
import {tempData} from "@/views/test/data-source";

const mockSelectorChange = (e) => {
  console.log('数值选择器变化',e)
  data.taskDataSelector.startX = e.startX
  data.taskDataSelector.endX = e.endX
  data.taskDataSelector.endY = e.endY
  data.taskDataSelector.rand = e.rand
  setDefaultTask(e)
  main()
}
const pointerChange = (event) => {
  //console.log('曲线选择器变化')
  data.point1[0] = event['p1'][0]
  data.point1[1] = event['p1'][1]
  data.point2[0] = event['p2'][0]
  data.point2[1] = event['p2'][1]
  main()
}
let data = reactive({
  selectorShow: false,
  klineA: [],
  klineB: [],
  point1: [0.25, 0.75],
  point2: [0.75, 0.25],
  taskDataSelector: {
    xMax: 0,
    xMin: 0,
    startX: 0,
    endX: 0,
    endY: 0,
    rand: 0,
  }
});

const mockDb = reactive(
    {
      getTargetDayOpen: () => data.klineA[0], // 获取数据源的今开
      getDayOpen: () => 3280, // 获取今开
      getPreClose: () => 3256, // 获取昨收
      sysIndexDb: {
        MK000001: {
          initStatus: 0
        }
      },
      taskQueueMap: {}
    }
);
const mockIndexService = reactive({
  checkIsInit: (code) => {
    if (!mockDb.sysIndexDb[code]) {
      return false;
    }
    return mockDb.sysIndexDb[code].initStatus === 1;
  },
  setIsInit: (code,status) => {
    if (!mockDb.sysIndexDb[code]) {
      mockDb.sysIndexDb[code] = {}
    }
    mockDb.sysIndexDb[code].initStatus = status
  }
});


let xAxiosArr = computed(() => {
  let res = [];
  for (let i = 0; i < data.klineA.length; i++) {
    res.push(1740447000000 + i * 60)
  }
  return res;
})

class Task {
  END_Y = 3300;
  START_X = 50;
  END_X = 150;
  RANDOM = 0.001;
  START_PRICE = null;

  getPointForGlobal(point) {
    const boxWidth = this.END_X - this.START_X;
    const boxHeight = this.END_Y - this.START_PRICE
    return {
      x: this.END_X - boxWidth * (1 - point[0]),
      y: this.END_Y - boxHeight * (1 - point[1])
    }
  }
}

class TrendFollowAlgorithm {
  INIT_RATIO = 0.98;
  RM_RATIO = null;
  RM_PRICE = null;
  CURRENT_TASK = null;
  tempData = tempData;
  originCode = 'SH000001';
  mockCode = "MK000001";

  pullTask() {
    this.CURRENT_TASK = mockDb.taskQueueMap[this.mockCode][0]
  }

  // 生成B的数据
  generateBList(A) {
    const B = [];
    for (let x = 0; x < A.length; x++) {
      B.push(this.generateB(x, A[x]));
    }
    return B;
  }

  generateB(x, currentA) {
    const currentTask = this.CURRENT_TASK;
    let currentB;
    if ((!currentTask) || x <= currentTask.START_X || x >= currentTask.END_X) {
      if (this.RM_RATIO) {
        currentB = currentA * this.RM_RATIO;
      } else {
        // 如果没有实时比例,检查初始化状态,如果已经初始化过了,直接报错,有人动了redis缓存
        const isInit = mockIndexService.checkIsInit(this.mockCode);
        if (isInit) {
          throw Error('模拟产品已初始化,但是没有实时比例');
        }
        // 没有初始化过,使用默认比例,并设置初始化
        this.RM_RATIO = this.INIT_RATIO;
        mockIndexService.setIsInit(this.mockCode,1)
        currentB = currentA * this.RM_RATIO;
      }
    } else if (currentTask && x >= currentTask.START_X && x <= currentTask.END_X && currentTask.END_X !== null && currentTask.START_X !== null) {
      if (!currentTask.START_PRICE || Number(currentTask.START_PRICE) === 0) {
        //console.log('任务启动:', currentTask)
        // 第一次进入任务
        if (!this.RM_PRICE) {
          throw Error("任务开始时没有实时价格");
        }
        currentTask.START_PRICE = this.RM_PRICE;
        currentTask.START_RATIO = this.RM_PRICE / currentA
      }
      const p0G = currentTask.getPointForGlobal([0, 0])
      const p1G = currentTask.getPointForGlobal(data.point1)
      const p2G = currentTask.getPointForGlobal(data.point2)
      const p3G = currentTask.getPointForGlobal([1, 1])
      currentB = this.bezierCubic(p0G.y, p1G.y, p2G.y, p3G.y, this.findTForX(x, p0G.x, p1G.x, p2G.x, p3G.x));
      this.RM_RATIO = currentB / currentA;
    }
    //console.log(`x:${x},y${currentB}`)
    //currentB = Math.max(currentB += currentB * (Math.random() * this.CURRENT_TASK.RANDOM) * ((currentB + "").charCodeAt(0) % 2 === 0 ? 1 : -1), 0.01)
    this.RM_PRICE = currentB
    return currentB;
  }

  bezierCubic(p0, p1, p2, p3, t) {
    const t2 = t * t, t3 = t2 * t, oneMinusT = 1 - t, oneMinusT2 = oneMinusT * oneMinusT;
    return oneMinusT2 * oneMinusT * p0 + 3 * oneMinusT2 * t * p1 + 3 * oneMinusT * t2 * p2 + t3 * p3;
  }

  findTForX(currentX, p0, p1, p2, p3) {
    let tMin = 0, tMax = 1, tMid;
    for (let i = 0; i < 20; i++) { // 提高精度
      tMid = (tMin + tMax) / 2;
      const x = this.bezierCubic(p0, p1, p2, p3, tMid);
      if (Math.abs(x - currentX) < 0.5) return tMid;
      if (x < currentX) tMin = tMid;
      else tMax = tMid;
    }
    return tMid;
  }

  // 造点模拟数据
  generateTrendData() {
    return this.tempData.map(item => item.close)
  }
}


const setDefaultTask = (data) => {
  const task = new Task();
  task.START_X = data.startX
  task.END_X = data.endX
  task.END_Y = data.endY
  task.RANDOM = data.rand
  if (!mockDb.taskQueueMap['MK000001']) {
    mockDb.taskQueueMap['MK000001'] = [];
  }
  mockDb.taskQueueMap['MK000001'][0] = task
}

const main = () => {
  // 创建模拟数据生成器
  const sysIndexMockClient = new TrendFollowAlgorithm();
  mockIndexService.setIsInit(sysIndexMockClient.mockCode,0)
  // 拉取最新任务
  sysIndexMockClient.pullTask();
  // 获取模拟数据
  data.klineA = sysIndexMockClient.generateTrendData()
  // 执行任务
  data.klineB = sysIndexMockClient.generateBList(data.klineA)
}

document.addEventListener('keydown', (e) => {
  if (e.code === 'F2') {
    data.selectorShow = !data.selectorShow
  }
})
// 运行主函数
mockSelectorChange({
  startX: 50,
  endX: 150,
  endY: 3300,
  rand: 0.001
})
</script>

<style lang="scss" scoped>
.container {
  height: 100%;
  width: 100%;
  display: flex;
  justify-content: space-between;

  .controller {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
}
</style>
